

var DEFINITION_INTERFACE_DEFINE = `
abstract class Definition {
  Map<String, dynamic> toJson();
  void fromJson(Map<String, dynamic> json);
}
`;

var RESULT_INTEFACE_DEFINE = `
import 'Definition.dart';

class ResultBase<T> {
  int? code;
  String? msg;
  T? data;

  Map<String, dynamic> toJson() {
    return {
      "data": data,
      "code": code,
      "msg": msg
    };
  }

  fromJson(Map<String, dynamic> json) {
    data = json["data"];
    code = json["code"];
    msg = json["msg"];
  }
}

abstract class Result<T extends Definition> {
  int? code;
  String? msg;
  T? data;
  @override
  Map<String, dynamic> toJson() {
    return {
      "data": data?.toJson(),
      "code": code,
      "msg": msg
    };
  }

  T fromDataJson(Map<String, dynamic> json);

  @override
  fromJson(Map<String, dynamic> json) {
    data = json["data"] is! Map ? json["data"] : fromDataJson(json["data"]);
    code = json["code"];
    msg = json["msg"];
  }
}

abstract class ResultList<T extends Definition> {
  int? code;
  String? msg;
  List<T>? data;

  Map<String, dynamic> toJson() {
    return {
      "data": data?.map((e) => e.toJson()).toList(),
      "code": code,
      "msg": msg
    };
  }

  T fromDataJson(Map<String, dynamic> json);

  fromJson(Map<String, dynamic> json) {
    data = (json["data"] as List).map<T>((e) => fromDataJson(e)).toList();
    code = json["code"];
    msg = json["msg"];
  }
}
`


function definitionClassTmpl(CLASS_NAME, CLASS_REFS, PROPERTIES) {
  return `
import 'Definition.dart';
${CLASS_REFS}
class ${CLASS_NAME} extends Definition {
  ${PROPERTIES}
}
  `;
}

function definitionClassRefsTmpl(REFS) {
  return REFS.map(ref=> {
    if(!ref) return "";
    return `import '${ref}.dart';\n`
  }).join("");
}

function definitionPropertiesTmpl(definition) {
  return `
${
  (()=> {
    return Object.keys(definition.properties).map((propertyName)=> {
      var property = definition.properties[propertyName];
      if(property.$ref) {
        var className = definition.findRef(property.$ref).refClassName;
        return `\t${className}? ${propertyName};\n`;
      }
      var desc = property.description ? `\t/// ${property.description}\n` : "";
      if(property.enum) {
        desc += `\t/// 枚举值: ${property.enum.toString()}\n`;
      }
      switch (property.type) {
        case 'string':
          return `${desc}\tString? ${propertyName};\n`;
        case 'integer':
          return `${desc}\tint? ${propertyName};\n`;
        case 'float':
        case 'number':
          return `${desc}\tnum? ${propertyName};\n`;
        case 'array':
          var className = property.items.$ref ?
            definition.findRef(property.items.$ref).className :
            'dynamic'
          ;
          return `${desc}\tList<${className}>? ${propertyName};\n`;
        default:
          return `${desc}\tdynamic ${propertyName};\n`;
      }
    }).join("")
  })()
}
  @override
  Map<String, dynamic> toJson() {
    return {
${
  (()=> {
    return Object.keys(definition.properties).map((propertyName)=> {
      var property = definition.properties[propertyName];
      if(property.$ref) {
        // var className = definition.findRef(property.$ref).className;
        return `\t\t\t"${propertyName}": ${propertyName}?.toJson(),\n`;
      } if(property.type === "array") {
        return `\t\t\t"${propertyName}": ${propertyName}?.map((e) => e.toJson()).toList(),\n`
      } else {
        return `\t\t\t"${propertyName}": ${propertyName},\n`
      }
    }).join("")
  })()
}
    };
  }

  @override
  void fromJson(Map<String, dynamic> json) {
${
  (()=> {
    return Object.keys(definition.properties).map((propertyName)=> {
      var property = definition.properties[propertyName];
      if(property.$ref) {
        var className = definition.findRef(property.$ref).refClassName;
        return `\t\t${propertyName} = json["${propertyName}"] == null ? null : (${className}()..fromJson(json["${propertyName}"]));\n`;
      } if(property.type === "array") {
        if(property.items.$ref) {
          var className = definition.findRef(property.items.$ref).className;
          return `\t\t\t${propertyName} = (json["${propertyName}"] as List).map<${className}>((e) => ${className}()..fromJson(e)).toList();\n`
        } else {
          var className = 'dynamic'
          switch (property.items.type) {
            case 'string':
                className = 'String';
              break;
              case 'integer':
                className = 'int';
              case 'float':
              case 'number':
                className = 'num';
            default:
              break;
          }
          return `\t\t${propertyName} = (json["${propertyName}"] as List).map<${className}>((e) => e as ${className}).toList();\n`
        ;
        }
      } else {
        return `\t\t${propertyName} = json["${propertyName}"];\n`;
      }
    }).join("")
  })()
}
  }
  `;
}



function classTmpl(ClassName, ClassMethods, REFS){
  return `
import 'dart:async';
import 'package:camera/utils/ApiService.dart';
${REFS}

class ${ClassName} {
${ClassMethods}
}`
} 
  
function methodTmpl(api){
  var OperationId = api.operationId.replace(/\_\d+$/, '');
  var Summary = api.summary;
  var Path = api.path;
  var Method = api.method;
  var host = api.host

  var paramsRegex = /(\{\w+\})/gm;
  var params = Path.match(paramsRegex) || [];
  var _url = Path;
  var paramsArgs = [];
  for(var i=0;i<params.length;i++) {
    var param = params[i].replace(/[\{\}]/g, "");
    _url = _url.replace(params[i], "$"+param);
    paramsArgs.push(`String ${param}, `);
  }

  var queryArgs = [];
  var queryStrArray = [];
  if(api.queryParams) {
    for(var i=0;i< api.queryParams.length;i++) {
      var param = api.queryParams[i];
      var paramName = param.name;
      queryStrArray.push(`${paramName}=\$\{${paramName} ?? "" \}`);
      switch (param.format) {
        case 'string':
          queryArgs.push(`String ${paramName}, `);
          break;
        case 'integer':
          queryArgs.push(`int ${paramName}, `);
          break;
        case 'float':
          queryArgs.push(`num ${paramName}, `);
          break;
        default:
          queryArgs.push(`dynamic ${paramName}, `);
          break;
      }
    }
    if(queryStrArray.length>0) {
      _url += "?" + queryStrArray.join("&");
    }
  }

  if(Method == "put" || Method == "post") {
    var ResponseParam = api.parseResponse && api.parseResponse() || "dynamic";
    var ParseBodyParam = api.parseBodyParam && api.parseBodyParam();
    return `
    static String ${OperationId}Path = "${host}${Path}";
    /// ${Summary}
    Future<${ResponseParam}> ${OperationId}(${paramsArgs.join("")}${queryArgs.join("")}${ParseBodyParam || ""}[ dynamic headers ]) async {
      var response = await ApiService.${Method}("${host}${_url}", ${!ParseBodyParam ? "null" : "data.toJson() "}, headers);
      return ${
        ResponseParam != "dynamic" ? `${ResponseParam}()..fromJson(response.data)` : "response.data"
      };
    }
    `
  }

  if(Method == "get" || Method == "delete") {
    var ResponseParam = api.parseResponse && api.parseResponse() || "dynamic";
    return `
    static String ${OperationId}Path = "${Path}";
    /// ${Summary}
    Future<${ResponseParam}> ${OperationId}(${paramsArgs.join("")}${queryArgs.join("")}[dynamic headers]) async {
      var response = await ApiService.${Method}("${host}${_url}", {}, headers);
      return ${
        ResponseParam != "dynamic" ? `${ResponseParam}()..fromJson(response.data)` : "response.data"
      };
    }
    `
  }

  return "";
}


function resultClassTmpl(className, extendsClassName, refClassName) {
  var originRefClassName;
  if(extendsClassName.includes('Result<List')) {
    extendsClassName = extendsClassName.replace('Result<List', 'ResultList<')
    var matches = /^ResultList\<(.+)\>$/g.exec(extendsClassName);
    originRefClassName = matches[1];
  } else if(extendsClassName.includes('Result')) {
    var matches = /^Result\<(.+)\>$/g.exec(extendsClassName);
    originRefClassName = matches[1];
  } else {
    return null
  }
  
  return `
import 'Result.dart';
import '${refClassName}.dart';

class ${className} extends ${extendsClassName.replace(originRefClassName, refClassName)} {
  @override
  ${refClassName} fromDataJson(Map<String, dynamic> json) {
    return ${refClassName}()..fromJson(json);
  }
}
`
}


module.exports = {
  DEFINITION_INTERFACE_DEFINE: DEFINITION_INTERFACE_DEFINE,
  RESULT_INTEFACE_DEFINE: RESULT_INTEFACE_DEFINE,
  definitionClassTmpl: definitionClassTmpl,
  definitionPropertiesTmpl: definitionPropertiesTmpl,
  definitionClassRefsTmpl: definitionClassRefsTmpl,
  classTmpl: classTmpl,
  shouldGenDefinition: true,
  resultClassTmpl: resultClassTmpl,
  methodTmpl: methodTmpl,
  shouldGenDefinition: true

}